﻿#include <windows.h>   // Windows API 核心头文件
#include <vector>      // 标准模板库向量容器

// 定义绘图模式枚举
enum DrawMode {
    MODE_LINE,  // 线段绘制模式
    MODE_RECT   // 矩形绘制模式
};

// 定义图形结构体
struct Shape {
    DrawMode mode;  // 图形类型（线段或矩形）
    POINT start;    // 图形起始点坐标
    POINT end;      // 图形结束点坐标
};

// 全局变量声明
HWND hWnd;          // 主窗口句柄
HINSTANCE hInst;    // 应用程序实例句柄
std::vector<Shape> shapes;  // 存储所有绘制图形的向量容器
DrawMode currentMode = MODE_LINE;  // 当前绘图模式，默认为线段模式
POINT currentStart;  // 当前绘制操作的起点坐标
bool isDrawing = false;  // 绘制状态标志，表示是否正在绘制

// 函数前置声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);  // 窗口过程函数
void DrawShapes(HDC hdc);  // 绘制所有已保存图形
void DrawCurrent(HDC hdc); // 绘制当前正在绘制的图形（预览）

// 应用程序入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    hInst = hInstance;  // 保存应用程序实例句柄

    // 初始化窗口类结构体
    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };  // 必须设置结构体大小
    wcex.style = CS_HREDRAW | CS_VREDRAW;      // 窗口样式：水平/垂直变化时重绘
    wcex.lpfnWndProc = WndProc;                // 设置窗口过程函数
    wcex.cbClsExtra = 0;                       // 无额外类内存
    wcex.cbWndExtra = 0;                       // 无额外窗口内存
    wcex.hInstance = hInstance;                // 应用程序实例
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 加载默认应用程序图标
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);   // 加载箭头光标
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 设置白色背景画刷
    wcex.lpszMenuName = NULL;                  // 无菜单
    wcex.lpszClassName = L"DrawingBoardClass"; // 窗口类名
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // 小图标

    // 注册窗口类
    if (!RegisterClassEx(&wcex)) {
        MessageBox(NULL, L"窗口注册失败!", L"错误", MB_ICONERROR);
        return 1;  // 注册失败时退出程序
    }

    // 创建主窗口
    hWnd = CreateWindow(
        L"DrawingBoardClass",      // 窗口类名
        L"简单画板",               // 窗口标题
        WS_OVERLAPPEDWINDOW,       // 标准窗口样式
        CW_USEDEFAULT,             // 默认水平位置
        CW_USEDEFAULT,             // 默认垂直位置
        800,                       // 窗口宽度
        600,                       // 窗口高度
        NULL,                      // 无父窗口
        NULL,                      // 无菜单
        hInstance,                 // 应用程序实例
        NULL                       // 无额外创建数据
    );

    // 检查窗口是否创建成功
    if (!hWnd) {
        MessageBox(NULL, L"窗口创建失败!", L"错误", MB_ICONERROR);
        return 1;
    }

    // 创建菜单系统
    HMENU hMenu = CreateMenu();      // 创建主菜单
    HMENU hDrawMenu = CreateMenu();  // 创建绘图子菜单

    // 添加菜单项
    AppendMenu(hDrawMenu, MF_STRING, 101, L"线段"); // 线段菜单项
    AppendMenu(hDrawMenu, MF_STRING, 102, L"矩形"); // 矩形菜单项
    AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hDrawMenu, L"绘图"); // 添加子菜单到主菜单
    SetMenu(hWnd, hMenu);  // 将菜单附加到窗口

    // 显示并更新窗口
    ShowWindow(hWnd, nCmdShow);  // 显示窗口
    UpdateWindow(hWnd);          // 发送WM_PAINT消息立即重绘

    // 主消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);  // 转换键盘消息
        DispatchMessage(&msg);   // 分发消息到窗口过程
    }

    return (int)msg.wParam;  // 程序结束时返回消息参数
}

// 窗口过程函数 - 处理所有窗口消息
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    PAINTSTRUCT ps;  // 绘图结构
    HDC hdc;         // 设备上下文句柄

    // 处理不同的窗口消息
    switch (message) {
    case WM_CREATE:
        // 窗口创建时执行初始化
        break;

    case WM_COMMAND:
        // 处理菜单命令
        switch (LOWORD(wParam)) {
        case 101:  // 线段菜单项
            currentMode = MODE_LINE;
            MessageBox(hWnd, L"当前模式: 线段", L"模式", MB_ICONINFORMATION);
            break;
        case 102:  // 矩形菜单项
            currentMode = MODE_RECT;
            MessageBox(hWnd, L"当前模式: 矩形", L"模式", MB_ICONINFORMATION);
            break;
        }
        break;

    case WM_LBUTTONDOWN:
        // 鼠标左键按下 - 开始绘制
        isDrawing = true;  // 设置绘制标志
        currentStart.x = LOWORD(lParam);  // 保存起点X坐标
        currentStart.y = HIWORD(lParam);  // 保存起点Y坐标
        SetCapture(hWnd);  // 捕获鼠标，即使移出窗口也能接收消息
        break;

    case WM_MOUSEMOVE:
        // 鼠标移动 - 实时更新预览
        if (isDrawing) {
            // 请求重绘整个窗口（会触发WM_PAINT消息）
            InvalidateRect(hWnd, NULL, TRUE);
        }
        break;

    case WM_LBUTTONUP:
        // 鼠标左键释放 - 结束绘制
        if (isDrawing) {
            isDrawing = false;  // 清除绘制标志
            ReleaseCapture();   // 释放鼠标捕获

            // 创建新图形对象
            Shape newShape;
            newShape.mode = currentMode;    // 设置图形类型
            newShape.start = currentStart;  // 设置起点
            newShape.end.x = LOWORD(lParam); // 设置终点X坐标
            newShape.end.y = HIWORD(lParam); // 设置终点Y坐标

            shapes.push_back(newShape);     // 添加到图形列表

            // 请求重绘整个窗口
            InvalidateRect(hWnd, NULL, TRUE);
        }
        break;

    case WM_PAINT:
        // 窗口需要重绘
        hdc = BeginPaint(hWnd, &ps);  // 开始绘制

        // 绘制所有已保存的图形
        DrawShapes(hdc);

        // 如果正在绘制，添加当前图形的预览
        if (isDrawing) {
            DrawCurrent(hdc);
        }

        EndPaint(hWnd, &ps);  // 结束绘制
        break;

    case WM_DESTROY:
        // 窗口销毁时退出应用程序
        PostQuitMessage(0);
        break;

    default:
        // 未处理的消息交给默认窗口过程处理
        return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;  // 消息已处理
}

// 绘制所有已保存的图形
void DrawShapes(HDC hdc) {
    // 创建黑色实线画笔（宽度为2）
    HPEN hPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
    // 选入设备上下文并保存原画笔
    HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);

    // 遍历所有图形
    for (const auto& shape : shapes) {
        switch (shape.mode) {
        case MODE_LINE:  // 绘制线段
            MoveToEx(hdc, shape.start.x, shape.start.y, NULL);  // 移动到起点
            LineTo(hdc, shape.end.x, shape.end.y);             // 画线到终点
            break;
        case MODE_RECT:  // 绘制矩形
            // 绘制矩形（自动使用当前画笔）
            Rectangle(hdc, shape.start.x, shape.start.y, shape.end.x, shape.end.y);
            break;
        }
    }

    // 恢复原画笔并删除创建的画笔
    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
}

// 绘制当前正在绘制的图形（预览）
void DrawCurrent(HDC hdc) {
    // 创建灰色虚线画笔（宽度为1）
    HPEN hPen = CreatePen(PS_DASH, 1, RGB(128, 128, 128));
    // 选入设备上下文并保存原画笔
    HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);

    // 获取当前鼠标位置（屏幕坐标）
    POINT currentEnd;
    currentEnd.x = LOWORD(GetMessagePos());
    currentEnd.y = HIWORD(GetMessagePos());

    // 将屏幕坐标转换为窗口客户区坐标
    ScreenToClient(hWnd, &currentEnd);

    // 根据当前模式绘制预览图形
    switch (currentMode) {
    case MODE_LINE:  // 线段预览
        MoveToEx(hdc, currentStart.x, currentStart.y, NULL);
        LineTo(hdc, currentEnd.x, currentEnd.y);
        break;
    case MODE_RECT:  // 矩形预览
        Rectangle(hdc, currentStart.x, currentStart.y, currentEnd.x, currentEnd.y);
        break;
    }

    // 恢复原画笔并删除创建的画笔
    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
}